package com.rogan.rpc.client;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.rogan.rpc.client.net.BioNetClient;
import com.rogan.rpc.client.net.NetClient;
import com.rogan.rpc.message.MessageProtocol;
import com.rogan.rpc.message.Request;
import com.rogan.rpc.message.Response;
import com.rogan.rpc.server.ServiceInfo;
import com.rogan.rpc.server.ServiceInfoDiscoverer;

/**
 * 客户端存根代理
 * 
 * @author Administrator
 *
 */
public class ClientStubProxyFactory {

	public ClientStubProxyFactory() {
	}

	private ServiceInfoDiscoverer sid;

	private Map<String, MessageProtocol> supportMessageProtocols;

	private NetClient netClient;

	private Map<Class<?>, Object> objectCache = new HashMap<>();

	/**
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getProxy(Class<T> clazz) {
		T obj = (T) this.objectCache.get(clazz);
		if (obj == null) {
			obj = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz },
					new ClientStubInvocationHandler(clazz));
		}
		return obj;
	}

	public void setServiceInfoDiscoverer(ServiceInfoDiscoverer sid) {
		this.sid = sid;
	}

	/**
	 * 服务发现 协议层 网络层
	 * 
	 * @author Administrator
	 *
	 */
	public class ClientStubInvocationHandler implements java.lang.reflect.InvocationHandler {
		private Class<?> interf;

		public ClientStubInvocationHandler(Class<?> interf) {
			super();
			this.interf = interf;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Exception {

			// 获得服务信息
			String serviceName = this.interf.getName();
			ServiceInfo sinfo = sid.getServiceInfo(serviceName);

			if (sinfo == null) {
				throw new Exception("远程服务不存在！");
			}

			// 构造requset对象
			Request request = new Request();

			Class<?>[] classes = proxy.getClass().getInterfaces();
			String className = classes[0].getName();

			request.setServiceName(className);
			request.setParameters(args);
			request.setParameterTypes(method.getParameterTypes());
			request.setMethod(method.getName());

			// 编组消息
			MessageProtocol protocol = supportMessageProtocols.get(sinfo.getProtocol());
			byte[] data = protocol.marshallingRequest(request);
			// 发送请求
			byte[] repData = netClient.sendRequest(data, sinfo);

			// 解组响应消息
			Response rsp = protocol.unmarshallingResponse(repData);

			if (rsp.getException() != null) {
				throw rsp.getException();
			}
			return rsp.getReturnValue();

		}

	}

	public NetClient getNetClient() {
		return netClient;
	}

	public void setNetClient(NetClient netClient) {
		this.netClient = netClient;
	}

	public ServiceInfoDiscoverer getSid() {
		return sid;
	}

	public void setSid(ServiceInfoDiscoverer sid) {
		this.sid = sid;
	}

	public Map<String, MessageProtocol> getSupportMessageProtocols() {
		return supportMessageProtocols;
	}

	public void setSupportMessageProtocols(Map<String, MessageProtocol> supportMessageProtocols) {
		this.supportMessageProtocols = supportMessageProtocols;
	}
}
